using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Globalization;
using ResourceBlender.Express.Validators;
using System.ComponentModel;
using System.Data.Common;
using System.Data;
using System.Windows.Controls.Primitives;
using ResourceBlender.DAL;
using ResourceBlender.Core;

namespace ResourceBlender.Express {
    /// <summary>
    /// A window for adding or editing an element and the resource it uses.
    /// </summary>
    public partial class WinAddResource : Window {
        private ObservableResource resource;

        /// <summary>
        /// Gets or sets the resource being edited.
        /// </summary>
        /// <value>The resource.</value>
        public ObservableResource Resource {
            get { return resource; }
            set {
                resource = value;
                DataContext = resource;
            }
        }

        public WinAddResource(int resourceId) {
            InitializeComponent();
            resource = new ObservableResource();
            if(resourceId > 0) { // could be modified to allow creation of new resources
                resource.ID = resourceId;
                // untested: not sure how this will work since there are no languages
            }
            LoadResource(resourceId);
            PopulateLanguages();
        }

        public WinAddResource(ObservableResource resource) {
            InitializeComponent();
            this.Resource = resource;
            PopulateLanguages();
            LoadTranslatorComments();
        }

        /// <summary>
        /// Sets the text on the status message (null hides the statusbar and label).
        /// </summary>
        /// <param name="message">The message.</param>
        private void SetStatus(string message) {
            if(message == null) {
                prgStatus.Visibility = Visibility.Hidden;
                lblStatus.Visibility = Visibility.Hidden;
            } else {
                prgStatus.Visibility = Visibility.Visible;
                lblStatus.Visibility = Visibility.Visible;
                lblStatus.Content = message;
            }
        }

        /// <summary>
        /// Populates the textboxes for each language used by the application.
        /// </summary>
        private void PopulateLanguages() {
            stkTranslations.Children.RemoveRange(0, stkTranslations.Children.Count);
            IDictionary<string, RBTranslation> translations = Resource.Translations;
            foreach(KeyValuePair<string, RBTranslation> translation in translations) { // <code, translation>
                TranslationInput translationInput = new TranslationInput(Utils.GetCultureInfo(translation.Key));
                Binding bndTranslation = new Binding(string.Format("Translations[{0}]", translation.Key));
                bndTranslation.Mode = BindingMode.TwoWay;
                bndTranslation.Source = Resource;
                translationInput.SetBinding(TranslationInput.TranslationProperty, bndTranslation);
                translationInput.Margin = new Thickness(0, 2, 0, 2);
                stkTranslations.Children.Add(translationInput);
                translationInput.Expand();
            }
        }

        /// <summary>
        /// Loads the translator comments for the selected element.
        /// </summary>
        private void LoadTranslatorComments() {
            BackgroundWorker worker = new BackgroundWorker();
            SetStatus("Loading translator comments...");
            int resourceId = resource.ID;
            string[] languages = resource.Translations.Select(lang => lang.Key).ToArray();
            worker.DoWork += (s, dwe) => {
                Dictionary<string,string> comments = ResourceBlenderDAL.GetTranslatorComments(resourceId, languages);
                dwe.Result = comments;
            };
            worker.RunWorkerCompleted += (s, rwe) => {
                SetStatus(null);
                if(rwe.Error != null) {
                    DialogBox.Show(rwe.Error.Message, "Error Loading Translator Comments", DialogBox.DialogBoxType.OK, DialogBox.DialogBoxIcon.Error);
                } else {
                    Dictionary<string, string> comments = rwe.Result as Dictionary<string, string>;
                    if(comments != null) {
                        foreach(KeyValuePair<string, string> comment in comments) {
                            Resource.Translations[comment.Key].Comment = comment.Value;
                        }
                    }

                    SetStatus(null);
                }
            };
            worker.RunWorkerAsync();
        }

        /// <summary>
        /// Loads a new resource.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Controls.SelectionChangedEventArgs"/> instance containing the event data.</param>
        private void LoadResource(int resourceId) {
            BackgroundWorker worker = new BackgroundWorker();
            SetStatus("Loading resource...");
            worker.DoWork += (s, dwe) => {
                ObservableResource res = new ObservableResource(ResourceBlenderDAL.GetResource(resourceId));
                dwe.Result = res;
            };
            worker.RunWorkerCompleted += (s, rwe) => {
                SetStatus(null);
                if(rwe.Result is RBResource) {
                    Resource = new ObservableResource(rwe.Result as RBResource);
                    PopulateLanguages();
                } else {
                    DialogBox.Show("Error changing displayed resource: " + rwe.Error.Message, "Database Error", DialogBox.DialogBoxType.OK, DialogBox.DialogBoxIcon.Error);
                }
            };
            worker.RunWorkerAsync(resourceId);
        }

        /// <summary>
        /// Validates the user input, saves/updates the element and it's resource then closes the dialog.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void Save(object sender, ExecutedRoutedEventArgs e) {
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += (s, dwe) => {
                ResourceBlenderDAL.SaveResource(Resource);
            };
            worker.RunWorkerCompleted += (s, rwe) => {
                SetStatus(null);
                if(rwe.Error != null) {
                    DialogBox.ShowAlert(this, rwe.Result.ToString(), "Database Error");
                } else {
                    Close();
                }
            };
            SetStatus("Saving resource...");
            worker.RunWorkerAsync();
        }

        /// <summary>
        /// Closes the dialog without saving.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void CloseWindow(object sender, ExecutedRoutedEventArgs e) {
            Close();
        }

        /// <summary>
        /// Shows the larger editor.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void ShowFullEditor(object sender, ExecutedRoutedEventArgs e) {
            TextBox source = e.OriginalSource as TextBox;
            if(source == null) {
                return;
            }
            WinFullEditor editor = new WinFullEditor("Editor", source.Text);
            editor.Owner = this;
            editor.ShowDialog();
            if(editor.DialogResult == true) {
                source.Text = editor.Text;
            }
        }

        /// <summary>
        /// Shows a dialog to find resources which use a similar translation to the user's input
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void FindSimilar(object sender, ExecutedRoutedEventArgs e) {
            TextBox txtSource = e.OriginalSource as TextBox;
            WinFindResource dlg = new WinFindResource(new RBTranslation(e.Parameter.ToString(), txtSource.Text, ""), "");
            dlg.Owner = this;
            dlg.ShowDialog();
        }

        /// <summary>
        /// Automatically translates from the current UI language using Google Translate.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void AutoTranslate(object sender, ExecutedRoutedEventArgs e) {
            string uiCulture = CultureInfo.CurrentUICulture.Name;
            string englishName;
            try {
                englishName = CultureInfo.GetCultureInfo(uiCulture).EnglishName;
            } catch {
                englishName = uiCulture;
            }
            if(!resource.Translations.ContainsKey(uiCulture)) {
                DialogBox.ShowAlert(this, string.Format("{0} translation is not present", englishName), "Not Supported");
                //todo: make a dialog to choose from available google languages.
                // fill the dialog with cultures both supported by Google and present in the resource.
                return;
            }
            string googleSourceCode = GoogleTranslator.DotNetCode2GoogleCode(uiCulture),
                   destinationCode = e.Parameter.ToString(),
                   googleDestinationCode = GoogleTranslator.DotNetCode2GoogleCode(destinationCode);
            string textToTranslate = Resource.Translations[uiCulture].Translation.Trim();
            if(googleSourceCode.Length == 0 || googleDestinationCode.Length == 0) {
                DialogBox.ShowAlert(this, "Translation between the specified languages is not supported", "Not Supported");
            } else if(textToTranslate.Length == 0) {
                return;
            } else if(textToTranslate.Length > 4800) {
                DialogBox.ShowAlert(this, "Only strings up to 4800 characters in length can be translated", "Not Supported");
            } else {
                BackgroundWorker worker = new BackgroundWorker();
                worker.DoWork += (s, dwe) => {
                    try {
                        dwe.Result = GoogleTranslator.Translate(textToTranslate, googleSourceCode, googleDestinationCode);
                    } catch(Exception ex) {
                        dwe.Result = ex.Message;
                    }
                };
                worker.RunWorkerCompleted += (s, rwe) => {
                    if(rwe.Result is GoogleTranslator.TranslationResponse) {
                        GoogleTranslator.TranslationResponse response = rwe.Result as GoogleTranslator.TranslationResponse;
                        if(response.Status == 200) {
                            Resource.Translations[destinationCode].Translation = response.Data.TranslatedText;
                        } else {
                            DialogBox.ShowAlert(this,
                                string.Format("Error {0}: {1}",
                                    response.Status,
                                    response.Status == 400 ? string.Format("{0} translation not supported by {1}\n\n{2}", englishName, "Google", response.Details) : response.Details),
                            "Error translating resource");
                        }
                    } else {
                        DialogBox.ShowAlert(this, rwe.Result.ToString(), "Error translating resource");
                    }
                };
                worker.RunWorkerAsync();
            }
        }
    }
}